if (typeof Crypto == "undefined" || !Crypto.util) {
    (function () {

        var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        // Global Crypto object
        // with browser window or with node module
        var Crypto = (typeof window === 'undefined') ? exports.Crypto = {} : window.Crypto = {};

        // Crypto utilities
        var util = Crypto.util = {

            // Bit-wise rotate left
            rotl: function (n, b) {
                return (n << b) | (n >>> (32 - b));
            },

            // Bit-wise rotate right
            rotr: function (n, b) {
                return (n << (32 - b)) | (n >>> b);
            },

            // Swap big-endian to little-endian and vice versa
            endian: function (n) {

                // If number given, swap endian
                if (n.constructor == Number) {
                    return util.rotl(n, 8) & 0x00FF00FF |
                        util.rotl(n, 24) & 0xFF00FF00;
                }

                // Else, assume array and swap all items
                for (var i = 0; i < n.length; i++)
                    n[i] = util.endian(n[i]);
                return n;

            },

            // Generate an array of any length of random bytes
            randomBytes: function (n) {
                for (var bytes = []; n > 0; n--)
                    bytes.push(Math.floor(Math.random() * 256));
                return bytes;
            },

            // Convert a byte array to big-endian 32-bit words
            bytesToWords: function (bytes) {
                for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
                    words[b >>> 5] |= (bytes[i] & 0xFF) << (24 - b % 32);
                return words;
            },

            // Convert big-endian 32-bit words to a byte array
            wordsToBytes: function (words) {
                for (var bytes = [], b = 0; b < words.length * 32; b += 8)
                    bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
                return bytes;
            },

            // Convert a byte array to a hex string
            bytesToHex: function (bytes) {
                for (var hex = [], i = 0; i < bytes.length; i++) {
                    hex.push((bytes[i] >>> 4).toString(16));
                    hex.push((bytes[i] & 0xF).toString(16));
                }
                return hex.join("");
            },

            // Convert a hex string to a byte array
            hexToBytes: function (hex) {
                for (var bytes = [], c = 0; c < hex.length; c += 2)
                    bytes.push(parseInt(hex.substr(c, 2), 16));
                return bytes;
            },

            // Convert a byte array to a base-64 string
            bytesToBase64: function (bytes) {

                // Use browser-native function if it exists
                if (typeof btoa == "function") return btoa(Binary.bytesToString(bytes));

                for (var base64 = [], i = 0; i < bytes.length; i += 3) {
                    var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
                    for (var j = 0; j < 4; j++) {
                        if (i * 8 + j * 6 <= bytes.length * 8)
                            base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
                        else base64.push("=");
                    }
                }

                return base64.join("");

            },

            // Convert a base-64 string to a byte array
            base64ToBytes: function (base64) {

                // Use browser-native function if it exists
                if (typeof atob == "function") return Binary.stringToBytes(atob(base64));

                // Remove non-base-64 characters
                base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");

                for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
                    if (imod4 == 0) continue;
                    bytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
                        (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
                }

                return bytes;

            }

        };

        // Crypto character encodings
        var charenc = Crypto.charenc = {};

        // UTF-8 encoding
        var UTF8 = charenc.UTF8 = {

            // Convert a string to a byte array
            stringToBytes: function (str) {
                return Binary.stringToBytes(unescape(encodeURIComponent(str)));
            },

            // Convert a byte array to a string
            bytesToString: function (bytes) {
                return decodeURIComponent(escape(Binary.bytesToString(bytes)));
            }

        };

        // Binary encoding
        var Binary = charenc.Binary = {

            // Convert a string to a byte array
            stringToBytes: function (str) {
                for (var bytes = [], i = 0; i < str.length; i++)
                    bytes.push(str.charCodeAt(i) & 0xFF);
                return bytes;
            },

            // Convert a byte array to a string
            bytesToString: function (bytes) {
                for (var str = [], i = 0; i < bytes.length; i++)
                    str.push(String.fromCharCode(bytes[i]));
                return str.join("");
            }

        };

    })();
}

(function () {
    var qiniu = (typeof window === 'undefined') ? exports.qiniu = {} : window.qiniu = {};
    qiniu.config = {
        qiniuRegion: '',
        qiniuImageURLPrefix: '',
        qiniuUploadToken: '',
        qiniuUploadTokenURL: '',
        qiniuUploadTokenFunction: null,
        qiniuShouldUseQiniuFileName: false
    }
    // module.exports = {
    //     init: init,
    //     upload: upload,
    // }

    // 在整个程序生命周期中，只需要 init 一次即可
    // 如果需要变更参数，再调用 init 即可
    qiniu.init = function (options) {
        config = {
            qiniuRegion: '',
            qiniuImageURLPrefix: '',
            qiniuUploadToken: '',
            qiniuUploadTokenURL: '',
            qiniuUploadTokenFunction: null,
            qiniuShouldUseQiniuFileName: false
        };
        qiniu.updateConfigWithOptions(options);
    }

    qiniu.updateConfigWithOptions = function (options) {
        if (options.region) {
            qiniu.config.qiniuRegion = options.region;
        } else {
            console.error('qiniu uploader need your bucket region');
        }
        if (options.uptoken) {
            qiniu.config.qiniuUploadToken = options.uptoken;
        } else if (options.uptokenURL) {
            qiniu.config.qiniuUploadTokenURL = options.uptokenURL;
        } else if (options.uptokenFunc) {
            qiniu.config.qiniuUploadTokenFunction = options.uptokenFunc;
        }
        if (options.domain) {
            qiniu.config.qiniuImageURLPrefix = options.domain;
        }
        qiniu.config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName
    }

    qiniu.upload = function (filePath, success, fail, options) {
        if (null == filePath) {
            console.error('qiniu uploader need filePath to upload');
            return;
        }
        if (options) {
            qiniu.updateConfigWithOptions(options);
        }
        if (qiniu.config.qiniuUploadToken) {
            qiniu.doUpload(filePath, success, fail, options);
        } else if (qiniu.config.qiniuUploadTokenURL) {
            qiniu.getQiniuToken(function () {
                qiniu.doUpload(filePath, success, fail, options);
            });
        } else if (qiniu.config.qiniuUploadTokenFunction) {
            qiniu.config.qiniuUploadToken = qiniu.config.qiniuUploadTokenFunction();
            if (null == qiniu.config.qiniuUploadToken && qiniu.config.qiniuUploadToken.length > 0) {
                console.error('qiniu UploadTokenFunction result is null, please check the return value');
                return
            }
        } else {
            console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]');
            return;
        }
    }

    qiniu.doUpload = function (filePath, success, fail, options) {
        console.log(filePath)
        if (null == qiniu.config.qiniuUploadToken && qiniu.config.qiniuUploadToken.length > 0) {
            console.error('qiniu UploadToken is null, please check the init config or networking');
            return
        }
        var url = qiniu.uploadURLFromRegionCode(qiniu.config.qiniuRegion);
        var fileName = filePath.split('//')[1];
        if (options && options.key) {
            fileName = options.key;
        }
        var formData = {
            'token': qiniu.config.qiniuUploadToken
        };
        if (!qiniu.config.qiniuShouldUseQiniuFileName) {
            formData['key'] = fileName
        }
        wx.uploadFile({
            url: url,
            filePath: filePath,
            name: 'file',
            formData: formData,
            success: function (res) {
                var dataString = res.data
                try {
                    var dataObject = JSON.parse(dataString);
                    //do something
                    var imageUrl = qiniu.config.qiniuImageURLPrefix + '/' + dataObject.key;
                    dataObject.imageURL = imageUrl;
                    console.log(dataObject);
                    if (success) {
                        success(dataObject);
                    }
                    console.log("上传成功");
                } catch (e) {
                    console.log("上传失败", e);
                    console.log('parse JSON failed, origin String is: ' + dataString)
                    if (fail) {
                        fail(e);
                    }
                }
            },
            fail: function (error) {
                console.error(error);
                if (fail) {
                    fail(error);
                }
            }
        })
    }

    qiniu.getQiniuToken = function (callback) {
        wx.request({
            url: qiniu.config.qiniuUploadTokenURL,
            success: function (res) {
                var token = res.data.uptoken;
                if (token && token.length > 0) {
                    this.config.qiniuUploadToken = token;
                    if (callback) {
                        callback();
                    }
                } else {
                    console.error('qiniuUploader cannot get your token, please check the uptokenURL or server')
                }
            },
            fail: function (error) {
                console.error('qiniu UploadToken is null, please check the init config or networking: ' + error);
            }
        })
    }

    qiniu.uploadURLFromRegionCode = function (code) {
        var uploadURL = null;
        switch (code) {
            case 'ECN':
                uploadURL = 'https://up.qbox.me';
                break;
            case 'NCN':
                uploadURL = 'https://up-z1.qbox.me';
                break;
            case 'SCN':
                uploadURL = 'https://up-z2.qbox.me';
                break;
            case 'NA':
                uploadURL = 'https://up-na0.qbox.me';
                break;
            default:
                console.error('please make the region is with one of [ECN, SCN, NCN, NA]');
        }
        return uploadURL;
    }

})();


(function () {

    var C = (typeof window === 'undefined') ? exports.Crypto : window.Crypto;

    // Shortcuts
    var util = C.util,
        charenc = C.charenc,
        UTF8 = charenc.UTF8,
        Binary = charenc.Binary;

    // Public API
    var SHA1 = C.SHA1 = function (message, options) {
        var digestbytes = util.wordsToBytes(SHA1._sha1(message));
        return options && options.asBytes ? digestbytes :
            options && options.asString ? Binary.bytesToString(digestbytes) :
            util.bytesToHex(digestbytes);
    };

    // The core
    SHA1._sha1 = function (message) {

        // Convert to byte array
        if (message.constructor == String) message = UTF8.stringToBytes(message);
        /* else, assume byte array already */

        var m = util.bytesToWords(message),
            l = message.length * 8,
            w = [],
            H0 = 1732584193,
            H1 = -271733879,
            H2 = -1732584194,
            H3 = 271733878,
            H4 = -1009589776;

        // Padding
        m[l >> 5] |= 0x80 << (24 - l % 32);
        m[((l + 64 >>> 9) << 4) + 15] = l;

        for (var i = 0; i < m.length; i += 16) {

            var a = H0,
                b = H1,
                c = H2,
                d = H3,
                e = H4;

            for (var j = 0; j < 80; j++) {

                if (j < 16) w[j] = m[i + j];
                else {
                    var n = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
                    w[j] = (n << 1) | (n >>> 31);
                }

                var t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (
                    j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :
                    j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :
                    j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :
                    (H1 ^ H2 ^ H3) - 899497514);

                H4 = H3;
                H3 = H2;
                H2 = (H1 << 30) | (H1 >>> 2);
                H1 = H0;
                H0 = t;

            }

            H0 += a;
            H1 += b;
            H2 += c;
            H3 += d;
            H4 += e;

        }

        return [H0, H1, H2, H3, H4];

    };

    // Package private blocksize
    SHA1._blocksize = 16;

    SHA1._digestsize = 20;

})();


(function (global) {
    'use strict';
    var C = (typeof window === 'undefined') ? exports.Crypto : window.Crypto;
    var global = global || {};

    var _Base64 = global.Base64;
    var version = "2.1.9";
    var buffer;
    var b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var b64tab = function (bin) {
        var t = {};
        for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
        return t;
    }(b64chars);
    var fromCharCode = String.fromCharCode;
    var cb_utob = function (c) {
        if (c.length < 2) {
            var cc = c.charCodeAt(0);
            return cc < 0x80 ? c :
                cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) +
                    fromCharCode(0x80 | (cc & 0x3f))) :
                (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) +
                    fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
                    fromCharCode(0x80 | (cc & 0x3f)));
        } else {
            var cc = 0x10000 +
                (c.charCodeAt(0) - 0xD800) * 0x400 +
                (c.charCodeAt(1) - 0xDC00);
            return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) +
                fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) +
                fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
                fromCharCode(0x80 | (cc & 0x3f)));
        }
    };
    var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
    var utob = function (u) {
        return u.replace(re_utob, cb_utob);
    };
    var cb_encode = function (ccc) {
        var padlen = [0, 2, 1][ccc.length % 3],
            ord = ccc.charCodeAt(0) << 16 |
            ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) |
            ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
            chars = [
                b64chars.charAt(ord >>> 18),
                b64chars.charAt((ord >>> 12) & 63),
                padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
                padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
            ];
        return chars.join('');
    };
    var btoa = global.btoa ? function (b) {
        return global.btoa(b);
    } : function (b) {
        return b.replace(/[\s\S]{1,3}/g, cb_encode);
    };
    var _encode = buffer ? function (u) {
            return (u.constructor === buffer.constructor ? u : new buffer(u))
                .toString('base64')
        } :
        function (u) {
            return btoa(utob(u))
        };
    var encode = function (u, urisafe) {
        return !urisafe ?
            _encode(String(u)) :
            _encode(String(u)).replace(/[+\/]/g, function (m0) {
                return m0 == '+' ? '-' : '_';
            }).replace(/=/g, '');
    };
    var encodeURI = function (u) {
        return encode(u, true)
    };
    // decoder stuff
    var re_btou = new RegExp([
        '[\xC0-\xDF][\x80-\xBF]',
        '[\xE0-\xEF][\x80-\xBF]{2}',
        '[\xF0-\xF7][\x80-\xBF]{3}'
    ].join('|'), 'g');
    var cb_btou = function (cccc) {
        switch (cccc.length) {
            case 4:
                var cp = ((0x07 & cccc.charCodeAt(0)) << 18) |
                    ((0x3f & cccc.charCodeAt(1)) << 12) |
                    ((0x3f & cccc.charCodeAt(2)) << 6) |
                    (0x3f & cccc.charCodeAt(3)),
                    offset = cp - 0x10000;
                return (fromCharCode((offset >>> 10) + 0xD800) +
                    fromCharCode((offset & 0x3FF) + 0xDC00));
            case 3:
                return fromCharCode(
                    ((0x0f & cccc.charCodeAt(0)) << 12) |
                    ((0x3f & cccc.charCodeAt(1)) << 6) |
                    (0x3f & cccc.charCodeAt(2))
                );
            default:
                return fromCharCode(
                    ((0x1f & cccc.charCodeAt(0)) << 6) |
                    (0x3f & cccc.charCodeAt(1))
                );
        }
    };
    var btou = function (b) {
        return b.replace(re_btou, cb_btou);
    };
    var cb_decode = function (cccc) {
        var len = cccc.length,
            padlen = len % 4,
            n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) |
            (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) |
            (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) |
            (len > 3 ? b64tab[cccc.charAt(3)] : 0),
            chars = [
                fromCharCode(n >>> 16),
                fromCharCode((n >>> 8) & 0xff),
                fromCharCode(n & 0xff)
            ];
        chars.length -= [0, 0, 2, 1][padlen];
        return chars.join('');
    };
    var atob = global.atob ? function (a) {
        return global.atob(a);
    } : function (a) {
        return a.replace(/[\s\S]{1,4}/g, cb_decode);
    };
    var _decode = buffer ? function (a) {
            return (a.constructor === buffer.constructor ?
                a : new buffer(a, 'base64')).toString();
        } :
        function (a) {
            return btou(atob(a))
        };
    var decode = function (a) {
        return _decode(
            String(a).replace(/[-_]/g, function (m0) {
                return m0 == '-' ? '+' : '/'
            })
            .replace(/[^A-Za-z0-9\+\/]/g, '')
        );
    };
    var noConflict = function () {
        var Base64 = global.Base64;
        global.Base64 = _Base64;
        return Base64;
    };
    // export Base64
    global.Base64 = {
        VERSION: version,
        atob: atob,
        btoa: btoa,
        fromBase64: decode,
        toBase64: encode,
        utob: utob,
        encode: encode,
        encodeURI: encodeURI,
        btou: btou,
        decode: decode,
        noConflict: noConflict
    };
    // if ES5 is available, make Base64.extendString() available
    if (typeof Object.defineProperty === 'function') {
        var noEnum = function (v) {
            return {
                value: v,
                enumerable: false,
                writable: true,
                configurable: true
            };
        };
        global.Base64.extendString = function () {
            Object.defineProperty(
                String.prototype, 'fromBase64', noEnum(function () {
                    return decode(this)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64', noEnum(function (urisafe) {
                    return encode(this, urisafe)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64URI', noEnum(function () {
                    return encode(this, true)
                }));
        };
    }
    /*
    // that's it!
    if (global['Meteor']) {
        Base64 = global.Base64; // for normal export in Meteor.js
    }
    */

    //module.exports = global.Base64;
    C.Base64 = global.Base64;
})(this);